/*
 * Copyright (C) 2023 ab_skywalker@163.com All Rights Reserved.
 *
 * SPDX-License-Identifier: MIT
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 */
#include "sampletask.h"
#include "inittask.h"
#include "FreeRTOS.h"
#include "queue.h"
#include "task.h"
#include "drv_ad.h"
#include "drv_time.h"
#include <stdio.h>
#include "stm32g4xx_hal.h"
#include "util.h"

#define CONV_AD_VAL(x, i) (x * 3300 / 4096 / ((i % 2) == 0 ? 1 : 2))
#define CUR_AVERAGE_NUM 4

uint32_t curbufferA[64];
uint32_t curbufferB[64];
uint8_t bufferStateA = 0;
uint8_t bufferStateB = 0;
uint32_t datapos = 0;
uint32_t averagecur[CUR_AVERAGE_NUM], averagetmp[CUR_AVERAGE_NUM];
uint32_t targetcnt[CUR_AVERAGE_NUM] = {1000, 10000, 50000, 100000};
uint32_t tempcnt[CUR_AVERAGE_NUM];

uint32_t getAverageCurr(uint8_t type)
{
    if(type >= CUR_AVERAGE_NUM)
        return 0;
    return averagecur[type];
}

void computeAverageCurrent(uint32_t curr)
{
    for(uint8_t i = 0;i < CUR_AVERAGE_NUM;i++) {
        averagetmp[i] += curr;
        tempcnt[i]++;
        if(tempcnt[i] >= targetcnt[i]) {
            averagecur[i] = averagetmp[i] / targetcnt[i];
            tempcnt[i] = 0;
            averagetmp[i] = 0;
        }
    }
}

uint32_t convertcurrent(CURRENT_S curr)
{
    //换算为nA,ad计算时放大了1000倍，需要重新除掉。
    //采样值除以1，再乘以满偏（1V或2V）对应的nA值，才是最终结果。下面的计算省略了除以1
    //例如level为9，1V对应10nA，因此需要乘以10
    uint32_t tmp = 0;
    uint16_t tmpvalue = curr.valuel + curr.valueh * 256;
    switch (curr.level) {
        case 0:tmp = tmpvalue * 10000000000 / 1000;break;
        case 1:tmp = tmpvalue * 1000000000 / 1000;break;
        case 2:tmp = tmpvalue * 100000000 / 1000;break;
        case 3:tmp = tmpvalue * 10000000 / 1000;break;
        case 4:tmp = tmpvalue * 1000000 / 1000;break;
        case 5:tmp = tmpvalue * 100000 / 1000;break;
        case 6:tmp = tmpvalue * 10000 / 1000;break;
        case 7:tmp = tmpvalue * 1000 / 1000;break;
        case 8:tmp = tmpvalue * 100 / 1000;break;
        case 9:tmp = tmpvalue * 10 / 1000;break;
    }
    return tmp;
}

void computeCurrent(int32_t *advol, uint8_t cnt)
{
    int vollist[10];
    uint8_t i = 0;
    uint16_t tmp = 0;
    CURRENT_S realcurrent;
    vollist[0] = advol[0];
    vollist[1] = advol[5];
    vollist[2] = advol[6];
    vollist[3] = advol[7];
    vollist[4] = advol[8];
    vollist[5] = advol[1];
    vollist[6] = advol[2];
    vollist[7] = advol[3];
    vollist[8] = advol[4];
    vollist[9] = advol[9];
    
    for(i = 0;i < 10;i++) {
        if(vollist[i] > 120 && vollist[i] < 2482) {//ad结果大于100mv且小于2v，认为这一档结果有效
            tmp = CONV_AD_VAL(vollist[i], i);
            realcurrent.head = 0xa5;
            realcurrent.valuel = tmp;
            realcurrent.valueh = tmp >> 8;
            realcurrent.level = i;
            break ;
        }
    }
    if(i == 10) {
        realcurrent.head = 0xa5;
        realcurrent.valuel = 0;
        realcurrent.valueh = 0;
        realcurrent.level = 0;
    }
    computeAverageCurrent(convertcurrent(realcurrent));
    if(bufferStateA == 0) {
        curbufferA[datapos] = *(uint32_t *)(&realcurrent);
        datapos++;
        if(datapos >= 64) {
            datapos = 0;
            bufferStateA = 1;
            bufferStateB = 0;
        }
    } else if(bufferStateB == 0) {
        curbufferB[datapos] = *(uint32_t *)(&realcurrent);
        datapos++;
        if(datapos >= 64) {
            datapos = 0;
            bufferStateB = 1;
            bufferStateA = 0;
        }
    }
}
extern void cdc_acm_init(uint8_t busid, uint32_t reg_base);
extern void cdc_acm_data_send_with_dtr(uint8_t busid, uint8_t *ptr, uint32_t len);
void sampleTask(void * argument)
{
    int bufnum = 1;
    adInit();
    drvAdCurrCallbackRegister(computeCurrent);
    timerInit();
    cdc_acm_init(0, USB_BASE);
    while(1) {
        if(bufnum == 1 && bufferStateA == 1) {
            cdc_acm_data_send_with_dtr(0, (uint8_t *)curbufferA, sizeof(curbufferA));
            bufnum = 2;
        } else if(bufnum == 2 && bufferStateB == 1) {
            cdc_acm_data_send_with_dtr(0, (uint8_t *)curbufferB, sizeof(curbufferB));
            bufnum = 1;
        } else {
            msleep(1);
        }
    }

}
